package cn.seqdata.cxf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.core.MediaType;

import org.apache.cxf.Bus;
import org.apache.cxf.binding.BindingFactoryManager;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.feature.Feature;
import org.apache.cxf.feature.LoggingFeature;
import org.apache.cxf.jaxrs.JAXRSBindingFactory;
import org.apache.cxf.jaxrs.spring.AbstractSpringConfigurationFactory;
import org.apache.cxf.jaxrs.spring.JaxRsConfig;
import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationFeature;
import org.springframework.context.annotation.Import;

import cn.seqdata.cxf.interceptor.WrappedFeature;
import cn.seqdata.cxf.provider.ConstraintViolationExceptionMapper;
import cn.seqdata.cxf.provider.JacksonProvider;
import cn.seqdata.cxf.provider.JodaConverterProvider;

@Import(JaxRsConfig.class)
public abstract class SpringConfigurationFactory extends AbstractSpringConfigurationFactory {

	@Override
	protected Server createJaxRsServer() {
		// !!!特别处理，重载setDefaultResourceProvider，用SpringResourceFactory替换
		Bus bus = applicationContext.getBean(SpringBus.class);

		SpringJAXRSServerFactoryBean factory = new SpringJAXRSServerFactoryBean();
		factory.setApplicationContext(applicationContext);

		factory.setAddress(getAddress());
		factory.setTransportId(getTransportId());
		factory.setBus(bus);

		setJaxrsResources(factory);

		factory.setInInterceptors(getInInterceptors());
		factory.setOutInterceptors(getOutInterceptors());
		factory.setOutFaultInterceptors(getOutFaultInterceptors());
		factory.setFeatures(getFeatures());

		factory.setProviders(getJaxrsProviders());

		Map<Object, Object> extMaps = new HashMap<>();
		extMaps.put(MediaType.APPLICATION_JSON_TYPE.getSubtype(), MediaType.APPLICATION_JSON);
		factory.setExtensionMappings(extMaps);

		JAXRSBindingFactory bf = new JAXRSBindingFactory(bus);
		BindingFactoryManager manager = bus.getExtension(BindingFactoryManager.class);
		manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, bf);

		finalizeFactorySetup(factory);

		return factory.create();
	}

	@Override
	public List<Feature> getFeatures() {
		List<Feature> features = new ArrayList<>();

		features.add(new LoggingFeature());
		features.add(new WrappedFeature());
		features.add(new JAXRSBeanValidationFeature());

		return features;
	}

	@Override
	protected List<Object> getJaxrsProviders() {
		List<Object> providers = new ArrayList<>();

		// 处理joda数据类型如：DateTime/LocalDate/LocalTime/Period...
		providers.add(new JodaConverterProvider());
		// 自定义 ObjectMapper，也可以用 JacksonJsonProvider，但需要传入已经定义好的ObjectMapper
		providers.add(new JacksonProvider());// JacksonJsonProvider
		// javax.validations 支持，自动处理注解并抛出 ConstraintViolationException
		providers.add(new ConstraintViolationExceptionMapper());

		return providers;
	}
}
